package com.fintech.pangu.elasticsearch.validation;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Validator工具类
 *
 * @author chendongdong
 * @since 1.0.0
 **/
public class ValidatorsUtil {

    private static final Logger logger = LoggerFactory.getLogger(ValidatorsUtil.class);

    private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    private static final String DEFAULT_DELIMITER = ":";

    /**
     * Description
     * <br> 服务端参数有效性验证
     * <br> 验证失败时抛出ConstraintViolationException
     *
     * @param validator 校验接口类
     * @param object    验证的实体对象
     * @param groups    验证组
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static void validateWithException(Validator validator, Object object, Class... groups) throws ConstraintViolationException {
        Set constraintViolations = validator.validate(object, groups);
        if (CollectionUtils.isNotEmpty(constraintViolations)) {
            throw new ConstraintViolationException(constraintViolations);
        }
    }

    /**
     * Description
     * <br>  服务端参数有效性验证
     *
     * @param object 验证的实体对象
     * @param groups 验证组
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static void validateWithException(Object object, Class... groups) throws ConstraintViolationException {
        Set constraintViolations = validator.validate(object, groups);
        if (CollectionUtils.isNotEmpty(constraintViolations)) {
            ConstraintViolationException violationException = new ConstraintViolationException(constraintViolations);
            logger.warn("请求参数校验异常:{}", extractPropertyAndMessageAsStr(violationException));
            throw violationException;
        }
    }

    /**
     * Description
     * <br> 提取校验信息(格式:"错误信息")
     *
     * @param exception 异常对象
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static List<String> extractMessage(ConstraintViolationException exception) {
        Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
        List<String> errorMessages = new ArrayList<>(16);
        constraintViolations.stream().forEach(violation -> {
            errorMessages.add(violation.getMessage());
        });
        return errorMessages;
    }

    /**
     * Description
     * <br>  提取校验信息(格式:"属性信息:错误信息")
     *
     * @param exception 异常对象
     * @Return String
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static String extractPropertyAndMessageAsStr(ConstraintViolationException exception) {
        return extractPropertyAndMessageAsList(exception, DEFAULT_DELIMITER).toString();
    }


    /**
     * Description
     * <br>  提取校验信息(格式:"属性信息+分隔符+错误信息")
     *
     * @param exception 异常对象
     * @param separator 分隔符
     * @Return String
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static String extractPropertyAndMessageAsStr(ConstraintViolationException exception, String separator) {
        return extractPropertyAndMessageAsList(exception, separator).toString();
    }


    /**
     * Description
     * <br> 提取校验信息(格式:"属性信息+分隔符+错误信息")
     *
     * @param exception 异常对象
     * @param separator 分隔符
     * @Return List
     * @date 2019/04/12
     * @author chendongdong
     **/
    public static List<String> extractPropertyAndMessageAsList(ConstraintViolationException exception, String separator) {
        Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
        String delimiter = ObjectUtils.isEmpty(separator) ? DEFAULT_DELIMITER : separator;
        List<String> errorMessageList = new ArrayList<>(16);
        constraintViolations.stream().forEach(violation -> {
            String errorMessage = String.join(delimiter, violation.getPropertyPath().toString(), violation.getMessage());
            errorMessageList.add(errorMessage);
        });
        return errorMessageList;
    }
}
